Skip to content

docs(shipping): #549 S2-2 N03 TOCTOU threat model and P-N03 proposal (Phase 1) - #583

Closed
raylei50653 wants to merge 6 commits into
mainfrom
docs/549-s2-2-n03-proposal
Closed

raylei50653 wants to merge 6 commits into
mainfrom
docs/549-s2-2-n03-proposal

Conversation

@raylei50653

@raylei50653 raylei50653 commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

Summary

Phase 1 of the #549 S2-2 N03 TOCTOU work (ADR 028 D5, CC-536-01-02, #550): threat model, alternatives, contract matrix and reproducible research evidence for P-N03 revision 3c.

Docs and research prototype only. No production loader, auditor, launcher, N03 bytes, allowlist, installed package or pin changes. N03 MB-41 stays OPEN, S2-2 stays PARTIAL, aggregate load_verification.byte_scope stays hashed_before_load, and qualified V5 stays UNRESOLVED. distribution.status=local-only, owner_confirmation=null.

Phase verdict: PARTIAL. Gate 1 is not a stop; production implementation (Phase 2) waits on owner decisions D-N03-1..6.

Design

  • Host:
    1. Open N03 once (S), hash the buffer.
    2. Create a sealed memfd saccade-n03:src-fd=<S> (MFD_NOEXEC_SEAL, four seals) and hash it again on readback.
    3. dlopen("/proc/self/fd/<M>").
    4. Post-check that the mapping holding l_ld is M (device+inode).
    5. Keep M open, in a process-wide registry keyed by SHA-256 + source path.
  • Auditor:
    • Identify each mapped object from its /proc/self/maps record (path+inode).
    • Names that do not identify their mapping (descriptor names, unresolved/relative/spoofed names) are refused unless they are the operator memfd.
    • The operator memfd must have its label, seals, d_path(S) == the fixed operator path, matching device/inode, and the same bytes as the fixed file.

Findings worth knowing even without this design

  • Main's auditor accepts three descriptor-backed loads that evade N03 classification:
    • B4: a deleted N03 copy via /proc/self/fd;
    • E1: a relative alias to a memfd;
    • E4: a planted … (deleted) path.
  • Main's pre-load hash + path dlopen loads bytes other than the hashed ones after a rename or in-place write (B1–B3).

Evidence (local-only raw evidence; hashes in the evidence JSON)

Item Result
#582 reproduction (installed auditor) pinned 0, foreign 127, unlabeled memfd 0
Matrix r10 (real loader, 45 cases) 45/45, inputs unchanged
GPU smoke r6 (real N03 op, fp32/fp16, CUDA graph capture + replay; RTX 5070 Ti, driver 617.42) 6/6; outputs bit-equal across load modes; output hashes only
Parser self-tests (auditor / host / GPU smoke) 14/14 each
Existing auditor/launcher real-loader regressions on the prototype 14/14
scripts/pre_push.sh on d0c50a55 exit 0; pytest 5670 passed, 52 skipped, 5 xfailed (local)
Remote CI on d0c50a55 run 38138969959: 7/7 jobs pass

Independent read-only Codex reviews

Round Commit Result
r1 cdf86953 1 blocker, 3 major, 3 minor
r2 4c7c0eba 1 major (provenance wording), 3 minor
r3 1d8d9abe no blocker/major
r4 7d1d04d1 no blocker/major; cleared for owner review
r5 99b0a86f no blocker/major; cleared for owner review

Every finding and its disposition is tabled in the document. Revision 3c addresses r5's two minor test-coverage items and has not been independently re-reviewed.

Failed predictions are retained: r1 C05, r2 C20 (MFD_NOEXEC_SEAL memfds do load), r4 (overlayfs device mismatch on WSL libcuda) and r5 F2.

Known limits / residuals (owner acceptance requested)

  • Provenance is an audit-time observation, as on main. It does not record the path a file was opened through (D-N03-5 / D-N03-6). The chunked comparison is not an atomic snapshot of a mutable file; byte equality (I1) does not depend on it.
  • Compatibility restrictions (fail closed):
    • a file literally named … (deleted);
    • an object whose l_ld is not file-backed (untested);
    • an object whose mapped path is ≥ PATH_MAX.
  • New availability requirement: memfd_create, /proc and executable memfd mappings; hosts lacking them are UNVERIFIED.
  • Not verified:
    • production implementation, full CLI, journal/report readers;
    • serial/double-buffer/seven-sequence replays;
    • SIGKILL under the proposal;
    • installed package/launcher;
    • V5 (driver 616.92 required).

Owner decisions requested

  • D-N03-1: accept the design.
  • D-N03-2: per-object N03 scope after Phase 2.
  • D-N03-3: no pathname fallback.
  • D-N03-4: auditor tightening.
  • D-N03-5 / D-N03-6: host-side source binding vs accepting the audit-time provenance residual.

Stays Draft; do not merge. Merge needs separate authorization naming the final head. Checkpoint writeback to #549/#536/#550 follows only an authorized merge and main CI.

🤖 Generated with Claude Code

raylei50653 and others added 6 commits October 11, 2026 19:06
…source

Phase 1 of the #549 S2-2 N03 TOCTOU work: threat model, alternatives,
contract matrix and research evidence for a host-sealed memfd whose
source descriptor and bytes the loader auditor verifies against the
fixed operator path. No production source changes; N03 MB-41 stays
OPEN and the aggregate byte scope stays hashed_before_load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Revision 2 identifies each mapped object from /proc/self/maps (path and
inode, not device: overlayfs reports different devices) so relative or
spoofed aliases to descriptors are refused, keeps the operator memfd
open with a process-wide registry and a post-dlopen mapping check, and
narrows I1/I2 and the failure semantics to what the checks establish.
Matrix r6 42/42, GPU smoke r2 6/6. N03 MB-41 stays OPEN.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Revision 3 states P2 as main's audit-time observation with the
historical open-path residual left to an owner decision, keys the
operator registry by SHA-256 and source path, discards overlong
/proc/self/maps records, compares device and inode for the memfd, and
records the '(deleted)'-name and non-file-backed l_ld restrictions.
Matrix r7 45/45, GPU smoke r3 6/6. N03 MB-41 stays OPEN.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Revision 3a closes the two minor review r3 items: the probe and GPU
smoke post-checks discard overlong /proc/self/maps records instead of
parsing their continuation, and the unfounded PATH_MAX bound on
kernel-rendered paths is removed. Matrix r8 45/45, GPU smoke r4 6/6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Revision 3b closes the review r4 items: the host and GPU smoke
post-checks read whole /proc/self/maps records with getline, the
auditor parser reads from a descriptor so it can be tested, and all
three pass 12 synthetic boundary cases each. The auditor's refusal of
mapped paths of PATH_MAX bytes or more is recorded as a compatibility
restriction. Matrix r9 45/45, GPU smoke r5 6/6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Revision 3c closes the review r5 coverage items: a header-shaped decoy
now starts the auditor's 65,535-byte continuation, and 8192/65535-byte
target records are tested with and without a final newline. Each of the
three parsers passes 14/14; matrix r10 45/45, GPU smoke r6 6/6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@raylei50653

Copy link
Copy Markdown
Owner Author

Closing as superseded (not merged). Not a merge conflict: GitHub reports this PR as mergeable. It is closed because its content is stale and later work has replaced it.

This Draft holds the Phase 1 research for the P-N03 rev 3c prototype (sealed memfd + maps identity). It showed that the candidate design was feasible. It did not make N03 a product-level security guarantee. The follow-up work has since landed on main:

Current status, per #550: MB-41 is CLOSED (bounded); S2-2 is PARTIAL; V5 qualified is UNRESOLVED; the installed package is UNVERIFIED; distribution is local-only. S2-3 is not authorized.

Merging the 1,962 lines here would put old status claims back on main. The diff and the review history stay on this PR for the record. This closure does not restart N03 research and does not open a new issue. It is the Draft cleanup step under #550 §0A.

@raylei50653
raylei50653 deleted the docs/549-s2-2-n03-proposal branch November 13, 2026 11:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant